"""
Version: 0.1
Author: CarpeDiem
Date: 2022/9/6
Description: 创建一个成绩表，用GUI进行可视化
"""

import tkinter as tk
import numpy as np
import matplotlib.pylab as plt
import tkinter.messagebox
import tkinter.filedialog
import sys
import pandas as pd

plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
'''重定向类'''


class myStdout():
    def __init__(self):
        # 将其备份
        self.stdoutbak = sys.stdout
        self.stderrbak = sys.stderr
        # 重定向
        sys.stdout = self
        sys.stderr = self

    def write(self, info):
        # info信息即标准输出sys.stdout和sys.stderr接收到的输出信息
        text.insert('end', info)  # 在多行文本控件最后一行插入print信息
        text.update()  # 更新显示的文本，不加这句插入的信息无法显示
        text.see(tkinter.END)  # 始终显示最后一行，不加这句，当文本溢出控件最后一行时，不会自动显示最后一行

    def restoreStd(self):
        # 恢复标准输出
        sys.stdout = self.stdoutbak
        sys.stderr = self.stderrbak


def Count():
    global stu_score
    sum_each = np.sum(stu_score, axis=1)  # 每位同学4门课总成绩
    max_score = np.max(sum_each)  # 总分最高分
    min_score = np.min(sum_each)  # 总分最高分
    avg_score = np.average(sum_each)  # 班级平均分
    print("最高总成绩：%d \n最低总成绩：%d \n平均总成绩： %d" %
          (max_score, min_score, np.round(avg_score, 2)))

    avg_each = np.average(stu_score, axis=0)  # 每门课平均分

    max_chinese = np.max(stu_score[:, 0])  # 最高语文成绩
    max_math = np.max(stu_score[:, 1])  # 最高数学成绩
    max_english = np.max(stu_score[:, 2])  # 最高英语成绩
    max_python = np.max(stu_score[:, 3])  # 最高Python成绩
    min_chinese = np.min(stu_score[:, 0])  # 最低语文成绩
    min_math = np.min(stu_score[:, 1])  # 最低数学成绩
    min_english = np.min(stu_score[:, 2])  # 最低英语成绩
    min_python = np.min(stu_score[:, 3])  # 最低Python成绩

    print("语文最高分：%d \n语文最低分：%d \n语文平均分： %d" %
          (max_chinese, min_chinese, np.round(avg_each[0], 2)))
    print("数学最高分：%d \n数学最低分：%d \n数学平均分： %d" %
          (max_math, min_math, np.round(avg_each[1], 2)))
    print("英语最高分：%d \n英语最低分：%d \n英语平均分： %d" %
          (max_english, min_english, np.round(avg_each[2], 2)))
    print("Python最高分：%d \nPython最低分：%d \nPython平均分： %d" %
          (max_python, min_python, np.round(avg_each[3], 2)))


'''文件导入函数'''


def UpLoad():
    global stu_score
    filename = tk.filedialog.askopenfilename(title="请选择一个数据文件",
                                             filetypes=[('csv', '*.csv')])
    if len(filename) != 0:
        df = pd.read_csv(filename, index_col=0)
        stu_score = np.loadtxt(filename,
                               dtype='int',
                               delimiter=',',
                               skiprows=1,
                               usecols=(1, 2, 3, 4),
                               encoding='UTF-8')
        myStdout()
        print(df)
        Count()

    else:
        tk.messagebox.showerror(title='警告', message='您没有选择任何文件')


'''各科成绩分布情况直方图'''


def Bar(num, title):
    '''
    绘制各科成绩直方图
    :param num: 各科成绩在数组中列的索引
    :param title: 直方图名称
    :return:
    '''
    fig = plt.figure()
    f = fig.add_subplot(1, 1, 1)
    f.hist(stu_score[:, num], bins=len(stu_score))  # bins——直方图柱数
    plt.title(title)
    plt.xlabel('score')
    plt.ylabel('Total Number')


'''每两科成绩之间的相关性分析'''


# 绘制散点图函数
def Correlation(num1, num2, name1, name2):
    fig = plt.figure()
    f = fig.add_subplot(1, 1, 1)
    f.scatter(num1, num2)
    plt.xlabel(name1)
    plt.ylabel(name2)
    plt.title(name1 + "和" + name2 + "成绩散点图")


'''可视化数据分析'''


def Plot():
    if stu_score.shape == (4, ):
        tk.messagebox.showerror(title='警告', message='您暂未导入数据')
    if f1.get() == 0 and f2.get() == 0 and f3.get() == 0 and f4.get(
    ) == 0 and f5.get() == 0 and f6.get() == 0 and f7.get() == 0 and f8.get(
    ) == 0 and f9.get() == 0 and f10.get() == 0 and f11.get() == 0 and f12.get(
    ) == 0 and f13.get() == 0:
        tk.messagebox.showerror(title='警告', message='您暂未选择数据分析方式')
    sum_each = np.sum(stu_score, axis=1)  # 每位同学4门课总成绩
    avg_each = np.average(stu_score, axis=0)  # 每门课平均分
    if f1.get() == 1:
        Bar(0, "Chinese Score")  # 语文
    if f2.get() == 1:
        Bar(1, "Math Score")  # 数学
    if f3.get() == 1:
        Bar(2, "English Score")  # 英语
    if f4.get() == 1:
        Bar(3, "Python Score")  # Python
    if f5.get() == 1:
        '''各科平均分直方图'''
        plt.figure()
        x = ["语文", "数学", "英语", "Python"]
        plt.bar(x, avg_each, width=0.3, label="各科平均分")
        for a, b in zip(x, np.round(avg_each, 2)):
            plt.text(a, b + 2, b, ha='center', fontsize=12)
        plt.yticks([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])  # 设置y轴的刻度
    if f6.get() == 1:
        plt.figure()
        plt.title('Total Score')
        plt.boxplot(sum_each,
                    medianprops={
                        'color': 'red',
                        'linewidth': '1.5'
                    },
                    meanline=True,
                    showmeans=True,
                    meanprops={
                        'color': 'blue',
                        'ls': '--',
                        'linewidth': '1.5'
                    },
                    flierprops={
                        "marker": "o",
                        "markerfacecolor": "red",
                        "markersize": 10
                    },
                    autorange=True)
        plt.yticks(np.arange(320, 400, 10))
    if f7.get() == 1:
        plt.figure()
        plt.title("各科成绩箱型图")
        labels = 'Chinese', 'Math', 'English', 'Python'
        plt.grid(True)  # 显示网格
        plt.boxplot([
            stu_score[:, 0], stu_score[:, 1], stu_score[:, 2], stu_score[:, 3]
        ],
                    medianprops={
                        'color': 'red',
                        'linewidth': '1.5'
                    },
                    meanline=True,
                    showmeans=True,
                    meanprops={
                        'color': 'blue',
                        'ls': '--',
                        'linewidth': '1.5'
                    },
                    flierprops={
                        "marker": "o",
                        "markerfacecolor": "red",
                        "markersize": 5
                    },
                    labels=labels)
        plt.yticks(np.arange(60, 100, 10))
    if f8.get() == 1:
        Correlation(stu_score[:, 0], stu_score[:, 1], "Chinese",
                    'Math')  # 语文与数学成绩散点图
    if f9.get() == 1:
        Correlation(stu_score[:, 0], stu_score[:, 2], "Chinese",
                    'English')  # 语文与英语成绩散点图
    if f10.get() == 1:
        Correlation(stu_score[:, 0], stu_score[:, 3], "Chinese",
                    'Python')  # 语文与Python成绩散点图
    if f11.get() == 1:
        Correlation(stu_score[:, 1], stu_score[:, 2], "Math",
                    'English')  # 数学与英语成绩散点图
    if f12.get() == 1:
        Correlation(stu_score[:, 1], stu_score[:, 3], "Math",
                    'Python')  # 数学与Python成绩散点图
    if f13.get() == 1:
        Correlation(stu_score[:, 2], stu_score[:, 3], "English",
                    'Python')  # 英语与Python成绩散点图
    plt.show()


'''初始化窗口'''
root = tk.Tk()
root.title("成绩分析")
root.geometry("1000x600")
root.resizable(width=False, height=False)  # 设置为不可拉伸
root.configure(bg="white")
label = tk.Label(root,
                 text="班 级 成 绩 分 析 系 统",
                 font=("黑体", 35),
                 bg="white",
                 fg="black",
                 pady=31)
label.pack()
label1 = tk.Label(root,
                  text="数据可视化分析",
                  font=("黑体", 18, "bold"),
                  bg="white",
                  fg="black")
label1.place(relx=0.4, rely=0.18)
'''导入本地文件'''
stu_score = np.array([1, 2, 3, 4])
button1 = tk.Button(root,
                    text="加载本地文件",
                    font=("黑体", 14),
                    fg="black",
                    bg="white",
                    bd=2.5,
                    command=UpLoad,
                    height=1,
                    width=18)
button1.place(relx=0.1, rely=0.85)
'''数据计算分析'''
text = tk.Text(root,
               font=("黑体", 11),
               fg="black",
               bg="white",
               bd=2.5,
               height=25,
               width=35)
text.place(relx=0.06, rely=0.18)
'''成绩直方图'''
label3 = tk.Label(root,
                  text="成绩直方图:",
                  font=("黑体", 15, "bold"),
                  bg="white",
                  fg="black")
label3.place(relx=0.4, rely=0.26)
f1 = tk.IntVar()
variable1 = tk.Checkbutton(root,
                           text="语文",
                           variable=f1,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable1.place(relx=0.4, rely=0.34)
f2 = tk.IntVar()
variable2 = tk.Checkbutton(root,
                           text="数学",
                           variable=f2,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable2.place(relx=0.5, rely=0.34)
f3 = tk.IntVar()
variable3 = tk.Checkbutton(root,
                           text="英语",
                           variable=f3,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable3.place(relx=0.6, rely=0.34)
f4 = tk.IntVar()
variable4 = tk.Checkbutton(root,
                           text="Python",
                           variable=f4,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable4.place(relx=0.7, rely=0.34)
f5 = tk.IntVar()
variable5 = tk.Checkbutton(root,
                           text="各科平均分",
                           variable=f5,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable5.place(relx=0.82, rely=0.34)
'''成绩箱型图'''
label4 = tk.Label(root,
                  text="成绩分析箱型图:",
                  font=("黑体", 15, "bold"),
                  bg="white",
                  fg="black")
label4.place(relx=0.4, rely=0.42)
f6 = tk.IntVar()
variable6 = tk.Checkbutton(root,
                           text="学生总成绩",
                           variable=f6,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable6.place(relx=0.4, rely=0.5)
f7 = tk.IntVar()
variable7 = tk.Checkbutton(root,
                           text="各科成绩汇总",
                           variable=f7,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable7.place(relx=0.6, rely=0.5)
'''每两科成绩之间的相关性分析'''
label5 = tk.Label(root,
                  text="学科成绩相关性(散点图):",
                  font=("黑体", 15, "bold"),
                  bg="white",
                  fg="black")
label5.place(relx=0.4, rely=0.58)
f8 = tk.IntVar()
variable8 = tk.Checkbutton(root,
                           text="语文 & 数学",
                           variable=f8,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable8.place(relx=0.4, rely=0.66)
f9 = tk.IntVar()
variable9 = tk.Checkbutton(root,
                           text="语文 & 英语",
                           variable=f9,
                           font=("黑体", 14),
                           bg="white",
                           fg="black")
variable9.place(relx=0.6, rely=0.66)
f10 = tk.IntVar()
variable10 = tk.Checkbutton(root,
                            text="语文 & Python",
                            variable=f10,
                            font=("黑体", 14),
                            bg="white",
                            fg="black")
variable10.place(relx=0.8, rely=0.66)
f11 = tk.IntVar()
variable11 = tk.Checkbutton(root,
                            text="数学 & 英语",
                            variable=f11,
                            font=("黑体", 14),
                            bg="white",
                            fg="black")
variable11.place(relx=0.4, rely=0.74)
f12 = tk.IntVar()
variable12 = tk.Checkbutton(root,
                            text="数学 & Python",
                            variable=f12,
                            font=("黑体", 14),
                            bg="white",
                            fg="black")
variable12.place(relx=0.6, rely=0.74)
f13 = tk.IntVar()
variable13 = tk.Checkbutton(root,
                            text="英语 & Python",
                            variable=f13,
                            font=("黑体", 14),
                            bg="white",
                            fg="black")
variable13.place(relx=0.8, rely=0.74)

button2 = tk.Button(root,
                    text="确定",
                    font=("黑体", 14),
                    fg="black",
                    bg="white",
                    bd=2,
                    width=11,
                    command=Plot)
button2.place(relx=0.76, rely=0.85)

root.mainloop()